package mover;
//authors: Jonathan Su and Jeff Forte

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.LinkedList;
import java.util.List;

import extensible.Behavior;
import extensible.Canvas;


/**
 *  Represents a shape that moves on its own
 *  @author Jonathan Su and Jeff Forte
 */
public abstract class Mover
{
    // state
	protected Point2D.Double myCenter;
	protected Point2D.Double myVelocity;
    protected Dimension mySize;
    protected Color myColor;
    private int myMaxTrail;
    private List<Point2D.Double> myTrail;
    protected List<Behavior> myBehaviors;


    /**
     * Construct a shape at the given position, with the given velocity, 
     * size, and color.  Also a size for its trail (if implemented).
     *
     * @param center position of the shape
     * @param size dimensions of the shape
     * @param velocity speed and direction of the shape
     * @param color color of the shape
     * @param trailSize number of lines to draw following the shape
     */
    public Mover (Point2D.Double center, Dimension size, Point2D.Double velocity, Color color, int trailSize, List<Behavior> behaviors)
    {
        myCenter = new Point2D.Double(center.getX(), center.getY());
        mySize = new Dimension(size.width, size.height);
        myVelocity = new Point2D.Double(velocity.getX(), velocity.getY());
        myColor = color;
        
        myMaxTrail = trailSize;
        myTrail = new LinkedList<Point2D.Double>();
        myTrail.add(new Point2D.Double(myCenter.x, myCenter.y));
        
        myBehaviors = behaviors;
    }
    
    public Mover (Point2D.Double center, Dimension size, Point2D.Double velocity, Color color)
    {
    	myCenter = new Point2D.Double(center.getX(), center.getY());
        mySize = new Dimension(size.width, size.height);
        myVelocity = new Point2D.Double(velocity.getX(), velocity.getY());
        myColor = color;
        
        myMaxTrail = 0;
        myTrail = new LinkedList<Point2D.Double>();
        myTrail.add(new Point2D.Double(myCenter.x, myCenter.y));
        
        myBehaviors = null;
    }



	/**
     * Describes how to "animate" the shape by changing its state.
     *
     * Currently, moves by the current velocity.
     *
     * @param bounds which encloses this shape
     */
    public void update (Canvas canvas)
    {
        myCenter.setLocation(myCenter.getX()+myVelocity.getX(), myCenter.getY()+myVelocity.getY());
        myTrail.add(new Point2D.Double(myCenter.getX(), myCenter.getY()));
        if (myTrail.size() >= myMaxTrail)
        {
            myTrail.remove(0);
        }
    }


    /**
     * Describes how to draw the shape on the screen.
     *
     * Currently, draw a trail of the shape's previous positions if it exists.
     * 
     * @param pen used to paint shape on the screen
     */
    public void paint (Graphics pen)
    {
        if (myMaxTrail > 0)
        {
            drawTrail(pen);
        }
    }


    /**
     * Reports shape's center. Allows necessary access by other packages.
     *
     * @return center of shape
     */
    public Point2D.Double getCenter ()
    {
        return myCenter;
    }

    /**
     * Reports shape's size. Allows necessary access by other packages.
     *
     * @return size of shape
     */
    public Dimension getSize ()
    {
        return mySize;
    }

    /**
     * Changes shape's color. Allows necessary access by other packages.
     */
    public void setSize (int width, int height)
    {
        mySize = new Dimension(width, height);
    }

	/**
     * Reports shape's velocity. Allows necessary access by other packages.
     *
     * @return velocity of shape
     */
    public Point2D.Double getVelocity ()
    {
        return myVelocity;
    }
    
    
	/**
     * Changes shape's velocity. Allows necessary access by other packages.
     */
    public void setVelocity (Point2D.Double point)
    {
        myVelocity.setLocation(point);
    }
    
	/**
     * Changes shape's velocity. Allows necessary access by other packages.
     */
    public void setVelocity (double x, double y)
    {
        myVelocity.setLocation(x, y);
    }

    /**
     * Resets shape's center.
     */
    public void setCenter (int x, int y)
    {
        myCenter = new Point2D.Double(x, y);
    }

    
    /**
     * Returns shape's left-most coordinate.
     */
    public int getLeft ()
    {
        return (int) getCenter().getX() - getSize().width / 2;
    }

    
    /**
     * Returns shape's top-most coordinate.
     */
    public int getTop ()
    {
        return (int) getCenter().getY() - getSize().height / 2;
    }


    /**
     * Returns shape's right-most coordinate.
     */
    public int getRight ()
    {
        return (int) getCenter().getX() + getSize().width / 2;
    }


    /**
     * Reports shape's bottom-most coordinate.
     *
     * @return bottom-most coordinate
     */
    public int getBottom ()
    {
        return (int) getCenter().getY() + getSize().height / 2;
    }
    
    /**
     * Reports shape's color. Allows necessary access by other packages.
     *
     * @return color of shape
     */
    public Color getColor ()
    {
        return myColor;
    }

    /**
     * Changes shape's color. Allows necessary access by other packages.
     */
    public void setColor (Color c)
    {
        myColor = c;
    }

    
	/**
	 * Gets the distance to a specified mover
	 * @param Mover within canvas
	 * @return Point2D distance of components between this and the target Mover
	 */
	public Point2D getDistance(Mover m){
		Point2D distance = new Point2D.Double(0,0);
		distance.setLocation(myCenter.getX() - m.myCenter.getX(), 
				myCenter.getY() - m.myCenter.getY());
		return distance;
	}
    
    
    /**
     * Draws a trail connecting the shape's previous positions.
     * 
     * @param pen used to paint shape on the screen
     */
    private void drawTrail (Graphics pen)
    {
        pen.setColor(myColor);
        // draw trail
        Point2D previous = myTrail.get(0);
        for (int k = 1; k < myTrail.size(); k++)
        {
            Point2D current = myTrail.get(k);
            if(current.distanceSq(previous) < 100) //arbitrary constant to make the tail not go across the screen when a mover wraps around.
            pen.drawLine((int)previous.getX(), (int)previous.getY(), (int)current.getX(), (int)current.getY());
            previous = current;
        }
    }
}
